/*
 * Handle kernel unexport symbols
 *
 * For unexported functions, we can find the address through
 * kallsyms and assign it to the relevant function pointer.
 * For unexported variables, we can find the address through
 * kallsyms and copy it to the relevant variable pointer, or
 * copy the variable value. For some immutable variables, it
 * is generally not a big problem to directly copy the
 * variable value.
 *
 * TODO: some variables value may change.
 *
 * brookxu@tencent.com 20220330
 */
#ifndef _SYMS_H
#define _SYMS_H

#include <linux/sched.h>
#include <linux/percpu.h>
#include <linux/interrupt.h>
#include <linux/cpuidle.h>
#include <linux/netdevice.h>
#include <linux/blk_types.h>
#include <linux/blkdev.h>
#include <linux/blk-mq.h>
#include "version.h"
#include "hook_tk5.h"

#ifdef CONFIG_X86_64
#include "include/arch/x86/include/asm/syscall.h"
#elif defined CONFIG_ARM64
typedef long (*syscall_fn_t)(const struct pt_regs *regs);
#endif

struct rq_flags_stat {
    unsigned long flags;
    struct pin_cookie cookie;
#ifdef CONFIG_SCHED_DEBUG
    /*
     * A copy of (rq::clock_update_flags & RQCF_UPDATED) for the
     * current pin context is stashed here in case it needs to be
     * restored in rq_repin_lock().
     */
    unsigned int clock_update_flags;
#endif
};
/*
 * This is mainly to avoid the runqueues undefined compilation
 * problem, We need to modify the implementation of macros such
 * as cpu_rq, and the modification results are as follows:
 * #define cpu_rq(cpu)		(per_cpu_ptr(runqueues, (cpu)))
 * #define this_rq()		this_cpu_ptr(runqueues)
 * #define raw_rq()		raw_cpu_ptr(runqueues)
 *
 * Tips: runqueues is changed from a percpu object to a percpu
 * pointer.
 */
#ifdef TK5
extern sys_call_ptr_t *p_sys_call_table[NR_syscalls+1];
extern struct mutex *p_module_mutex;
#define module_mutex_tk5 p_module_mutex
#else
#ifdef CONFIG_X86_64
extern sys_call_ptr_t *p_sys_call_table[__NR_syscall_max+1];
#elif defined CONFIG_ARM64
extern syscall_fn_t *p_sys_call_table[__NR_syscalls];
#endif
#endif
#define stat_sys_call_table (*p_sys_call_table)
extern struct rq __percpu *p_runqueues;
#define runqueues (p_runqueues)

#ifdef CONFIG_X86_64
extern void (*p_stat_do_syscall_64)(unsigned long nr, struct pt_regs *regs);
#define do_syscall_64(nr, regs) p_stat_do_syscall_64(nr, regs)
extern u64 (*p_stat_arch_irq_stat_cpu)(unsigned int cpu);
#define stat_arch_irq_stat_cpu(cpu) p_stat_arch_irq_stat_cpu(cpu)
#endif

extern void (*p_stat_sched_rqm_switch)(struct rq *rq, struct task_struct *prev, struct task_struct *next);
#define sched_rqm_switch(rq, prev, next) p_stat_sched_rqm_switch(rq, prev, next)

extern struct rq *(*p_stat_finish_task_switch)(struct task_struct *prev);
#define finish_task_switch(prev) p_stat_finish_task_switch(prev)
extern int (*p_idle_cpu)(int cpu);
#define idle_cpu(cpu) p_idle_cpu(cpu)
extern struct page *
(*p__alloc_pages_nodemask)(gfp_t gfp_mask, unsigned int order, int preferred_nid,
                                                         nodemask_t *nodemask);
#define __alloc_pages_nodemask(gfp_mask, order, preferred_nid, nodemask) p__alloc_pages_nodemask(gfp_mask, order, preferred_nid, nodemask)
extern u64 (*p_stat_arch_irq_stat)(void);
#define stat_arch_irq_stat() p_stat_arch_irq_stat()
extern blk_qc_t (*p_submit_bio)(struct bio *bio);
#define test_submit_bio(bio) p_submit_bio(bio)
extern void (*p_bio_endio)(struct bio *bio);
#define test_bio_endio(bio) p_bio_endio(bio)
extern void *(*p__kmalloc)(size_t size, gfp_t flags);
#define test__kmalloc(size, flags) p__kmalloc(size, flags)
extern void *(*p__kmalloc_node)(size_t size, gfp_t flags, int node);
#define test__kmalloc_node(size, flags, node) p__kmalloc_node(size, flags, node)
extern void *(*p_kmem_cache_alloc)(struct kmem_cache *s, gfp_t gfpflags);
#define test_kmem_cache_alloc(s, gfpflags) p_kmem_cache_alloc(s, gfpflags)
#ifdef TK5
extern bool (*p_blk_mq_dispatch_rq_list)(struct blk_mq_hw_ctx *hctx, struct list_head *list,
       unsigned int nr_budgets);
#define test_blk_mq_dispatch_rq_list(hctx, list, nr_budgets) p_blk_mq_dispatch_rq_list(hctx, list, nr_budgets)
#else
extern bool (*p_blk_mq_get_driver_tag)(struct request *rq);
#define test_blk_mq_get_driver_tag(rq) p_blk_mq_get_driver_tag(rq)
#endif
extern int (*p_stat_access_remote_vm)(struct mm_struct *mm, unsigned long addr,
         void *buf, int len, unsigned int gup_flags);
#define  test_access_remote_vm(mm, addr, buf, len, gup_flags) p_stat_access_remote_vm(mm, addr, buf, len, gup_flags)

extern void (*p_do_page_fault)(struct pt_regs *regs, unsigned long error_code, unsigned long address);
#define do_page_fault(regs, error_code, address) p_do_page_fault(regs, error_code, address);
#ifdef TK5
extern vm_fault_t (*p_handle_mm_fault)(struct vm_area_struct *vma, unsigned long address,
                unsigned int flags, struct pt_regs *regs);
#define handle_mm_fault(vma, address, flags, regs)  p_handle_mm_fault(vma, address, flags, regs)
extern void (*p_stat_psi_task_switch)(struct task_struct *prev, struct task_struct *next, bool sleep);
#define __psi_task_switch(prev, next, sleep) p_stat_psi_task_switch(prev, next, sleep)
#endif


extern struct task_struct * (*p_stat_pick_next_task)(struct rq *rq, struct task_struct *prev, struct rq_flags_stat *rf);
#define pick_next_task(rq, prev, rf) p_stat_pick_next_task(rq, prev, rf)

extern void (*p_stat_rcu_note_context_switch)(bool preempt);
#define rcu_note_context_switch(preempt) p_stat_rcu_note_context_switch(preempt)


extern int ksyms_init(void);
#endif
